<template>
  <div class="item-container" :class="['level-' + level]">
    <div class="item-row" style="min-width: 900px;">
      <!-- 展开/收起按钮 -->
      <button
        v-if="Array.isArray(item.value) && item.value.length > 0"
        @click="toggleExpand"
        class="expand-btn"
        v-once
      >
        <i :class="item.expanded ? 'fas fa-chevron-down' : 'fas fa-chevron-right'"></i>
      </button>
      <div v-else class="placeholder-btn" v-once></div>

      <!-- 层级指示器 -->
      <div class="level-indicator" v-once>
        {{ level }}
      </div>

      <!-- 键输入 -->
      <div class="input-group">
        <label class="input-label" v-once>属性</label>
        <input
          ref="propertyInput"
          v-model="localProperty"
          type="text"
          placeholder="请输入属性名"
          class="input-field"
          :class="{ 'input-error': hasDuplicateKey }"
          :readonly="!isEditable || (isEditing && localProperty !== '')"
          :disabled="!isEditable"
          @blur="handlePropertyBlur"
          @keyup.enter="handlePropertyBlur"
          @input="handlePropertyInput"
          @focus="recordCurrentFocus('property')"
        />
        <div v-if="hasDuplicateKey" class="error-text">
          同层级已存在相同属性名
        </div>
      </div>

      <!-- 备注输入 -->
      <div class="input-group">
        <label class="input-label" v-once>标题</label>
        <input
          ref="remarkInput"
          v-model="localRemark"
          type="text"
          placeholder="请输入标题信息"
          class="input-field"
          @blur="syncRemarkAndUpdate"
          @keyup.enter="syncRemarkAndUpdate"
          @input="handleRemarkInput"
          @focus="recordCurrentFocus('remark')"
        />
      </div>

      <!-- 值类型选择 -->
      <div class="type-select">
        <label class="input-label" v-once>类型</label>
        <select
          v-model="localType"
          class="select-field"
          @change="handleTypeChange"
        >
          <option value="text">文本</option>
          <option value="file">文件</option>
          <option value="image">图片</option>
          <option value="video">视频</option>
          <option value="object">对象</option>
        </select>
      </div>

      <!-- 值输入 -->
      <div class="input-group">
        <label class="input-label" v-once>属性值</label>

        <!-- 文本输入 -->
        <input
          ref="valueInput"
          v-if="localType === 'text'"
          v-model="localValue"
          type="text"
          placeholder="请输入属性值"
          class="input-field"
          @blur="syncValueAndUpdate"
          @keyup.enter="syncValueAndUpdate"
          @input="handleValueInput"
          @focus="recordCurrentFocus('value')"
        />

        <!-- 文件上传 -->
        <div v-else-if="localType === 'file'" class="file-upload">
          <input
            type="file"
            @change="handleFileUpload"
            class="file-input"
            :accept="item.accept || '*'"
          />
          <button
            v-if="localValue && localValue.startsWith('http')"
            @click="previewFile"
            class="preview-btn"
            title="预览文件"
          >
            <i class="fas fa-eye"></i>
          </button>
        </div>

        <!-- 图片上传 -->
        <div v-else-if="localType === 'image'" class="file-upload">
          <input
            type="file"
            @change="handleImageUpload"
            class="file-input"
            accept="image/*"
          />
          <div v-if="localValue" class="media-preview">
            <img :src="getFullMediaUrl(localValue)" :alt="localProperty" class="preview-img" />
            <button @click="previewFile" class="preview-btn" title="预览大图">
              <i class="fas fa-eye"></i>
            </button>
            <button @click="clearMedia('image')" class="delete-btn" title="删除">
              <i class="fas fa-times"></i>
            </button>
          </div>
        </div>

        <!-- 视频上传 -->
        <div v-else-if="localType === 'video'" class="file-upload">
          <input
            type="file"
            @change="handleVideoUpload"
            class="file-input"
            accept="video/*"
          />
          <div v-if="localValue" class="media-preview">
            <video :src="getFullMediaUrl(localValue)" controls class="preview-video" />
            <button @click="openVideoPreview" class="preview-btn" title="预览视频">
              <i class="fas fa-play"></i>
            </button>
            <button @click="clearMedia('video')" class="delete-btn" title="删除">
              <i class="fas fa-times"></i>
            </button>
          </div>
        </div>

        <!-- 对象类型提示 -->
        <div v-else-if="localType === 'object'" class="object-hint">
          对象类型，可添加子属性
        </div>
      </div>

      <!-- 操作按钮 -->
      <div class="action-buttons">
        <!-- 添加子节点 -->
        <button type="button"
          @click="addChild"
          class="add-btn"
          title="添加子属性"
        >
          <i class="fas">+</i>
        </button>

        <!-- 删除按钮 -->
        <button type="button"
          @click="remove"
          class="delete-btn"
          title="删除"
        >
          <i class="fas">-</i>
        </button>
      </div>
    </div>

    <!-- 子节点 -->
    <div v-if="Array.isArray(item.value) && item.value.length > 0 && item.expanded" class="children-container">
      <KeyValueItem
        v-for="child in item.value"
        :key="child.id"
        :item="child"
        :level="level + 1"
        :parent="item"
        :is-editable="isEditable"
        @add-child="(childItem) => $emit('add-child', childItem)"
        @remove="handleChildRemove(child.id)"
        @update="delayedEmitUpdate"
        @preview-video="(videoUrl) => $emit('preview-video', videoUrl)"
        @preview-file="(fileUrl) => $emit('preview-file', fileUrl)"
      />
    </div>
  </div>
</template>

<script>
import { getToken } from "@/utils/auth";
import { generateStableId } from '@/utils/idGenerator';
export default {
  name: 'KeyValueItem',
  components: {},
  props: {
    item: {
      type: Object,
      required: true
    },
    level: {
      type: Number,
      default: 0
    },
    parent: {
      type: Object,
      default: null
    },
    isEditing: {
      type: Boolean,
      default: false
    },
    isEditable: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      lastValidProperty: this.item.property || '',
      updateTimer: null,
      localProperty: this.item.property || '',
      localRemark: this.item.remark || '',
      localValue: this.item.value || '',
      localType: this.item.type || 'text',
      currentFocus: null
    };
  },
  watch: {
    'item.property': {
      handler(newVal) {
        this.localProperty = newVal;
        this.lastValidProperty = newVal;
      },
      immediate: true,
      deep: false
    },
    'item.remark': {
      handler(newVal) {
        this.localRemark = newVal;
      },
      immediate: true,
      deep: false
    },
    'item.value': {
      handler(newVal) {
        this.localValue = newVal;
      },
      immediate: true,
      deep: false
    },
    'item.type': {
      handler(newVal) {
        this.localType = newVal;
      },
      immediate: true,
      deep: false
    }
  },
  computed: {
    hasDuplicateKey() {
      return this.isPropertyDuplicate(this.localProperty);
    }
  },
  methods: {
    handlePropertyInput() {},
    handleRemarkInput() {},
    handleValueInput() {},

    removeNodeById(list, targetId) {
      for (let i = 0; i < list.length; i++) {
        if (list[i].id === targetId) {
          list.splice(i, 1);
          return true;
        }
        if (Array.isArray(list[i].value)) {
          const deleted = this.removeNodeById(list[i].value, targetId);
          if (deleted) return true;
        }
      }
      return false;
    },

    handleChildRemove(childId) {
      if (window.confirm('确定要删除此项吗？此操作不可恢复。')) {
        this.removeNodeById(this.item.value, childId);
        this.delayedEmitUpdate();
        this.resetFocus();
      }
    },

    toggleExpand() {
      this.item.expanded = !this.item.expanded;
      this.delayedEmitUpdate();
    },

    isPropertyDuplicate(propertyName) {
      if (!propertyName || !this.parent) return false;
      const siblings = this.parent.value || [];
      const currentIndex = siblings.indexOf(this.item);
      return siblings.some((item, index) => {
        return item.property === propertyName && index !== currentIndex;
      });
    },

    handlePropertyBlur() {
      if (this.isPropertyDuplicate(this.localProperty)) {
        this.localProperty = this.lastValidProperty;
        this.showToast('同层级已存在相同属性名，请修改', 'error');
        this.$nextTick(() => {
          this.$refs.propertyInput?.focus();
        });
        return;
      }

      const isChanged = this.item.property !== this.localProperty;
      this.item.property = this.localProperty;
      this.lastValidProperty = this.localProperty;

      if (isChanged) {
        this.delayedEmitUpdate();
      }

      this.$nextTick(() => {
        this.$refs.propertyInput?.focus();
      });
    },

    syncRemarkAndUpdate() {
      const isChanged = this.item.remark !== this.localRemark;
      if (isChanged) {
        this.item.remark = this.localRemark;
        this.delayedEmitUpdate();
      }
      this.$nextTick(() => {
        this.$refs.remarkInput?.focus();
      });
    },

    syncValueAndUpdate() {
      const isChanged = this.item.value !== this.localValue;
      if (isChanged) {
        this.item.value = this.localValue;
        this.delayedEmitUpdate();
      }
      this.$nextTick(() => {
        this.$refs.valueInput?.focus();
      });
    },

    addChild() {
      if (!Array.isArray(this.item.value)) {
        this.item.value = [];
      }
      if (this.localType !== 'object') {
        this.localType = 'object';
        this.item.type = 'object';
      }

      const newChild = {
        id: generateStableId(),
        property: '',
        value: '',
        remark: '',
        type: 'text',
        expanded: true
      };

      this.item.value.push(newChild);
      this.item.expanded = true;
      this.$emit('add-child', this.item);
      this.delayedEmitUpdate();
      this.resetFocus();
    },

    remove() {
      this.$emit('remove', this.item.id);
    },

    handleFileUpload(event) {
      const file = event.target.files[0];
      if (!file) return;

      const formData = new FormData();
      formData.append('file', file);
      this.$modal.loading("正在上传文件，请稍候...");

      const xhr = new XMLHttpRequest();
      const uploadUrl = process.env.VUE_APP_BASE_API + '/common/upload';
      xhr.open('POST', uploadUrl);
      xhr.setRequestHeader('Authorization', 'Bearer ' + this.getToken());
      xhr.withCredentials = true;

      xhr.onload = () => {
        this.$modal.closeLoading();
        if (xhr.status === 200) {
          try {
            const res = JSON.parse(xhr.responseText);
            if (res.code === 200) {
              this.localValue = res.url;
              setTimeout(() => {
                this.item.value = this.localValue;
                this.delayedEmitUpdate();
              }, 100);
              this.showToast('文件上传成功！');
            } else {
              this.showToast('文件上传失败：' + res.msg, 'error');
            }
          } catch (e) {
            this.showToast('文件上传失败，请重试', 'error');
          }
        } else {
          this.showToast('文件上传失败，请检查网络', 'error');
        }
      };

      xhr.onerror = () => {
        this.$modal.closeLoading();
        this.showToast('文件上传失败，请检查网络', 'error');
      };

      xhr.send(formData);
    },

    handleImageUpload(event) {
      const file = event.target.files[0];
      if (!file) return;

      const validTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
      if (!validTypes.includes(file.type)) {
        this.showToast('请上传正确的图片格式', 'error');
        return;
      }

      const maxSize = 5 * 1024 * 1024;
      if (file.size > maxSize) {
        this.showToast('图片大小不能超过5MB', 'error');
        return;
      }

      const formData = new FormData();
      formData.append('file', file);
      this.$modal.loading("正在上传图片，请稍候...");

      const xhr = new XMLHttpRequest();
      const uploadUrl = process.env.VUE_APP_BASE_API + '/common/upload';
      xhr.open('POST', uploadUrl);
      xhr.setRequestHeader('Authorization', 'Bearer ' + this.getToken());
      xhr.withCredentials = true;

      xhr.onload = () => {
        this.$modal.closeLoading();
        if (xhr.status === 200) {
          try {
            const res = JSON.parse(xhr.responseText);
            if (res.code === 200) {
              this.localValue = res.url;
              setTimeout(() => {
                this.item.value = this.localValue;
                this.delayedEmitUpdate();
              }, 100);
              this.showToast('图片上传成功！');
            } else {
              this.showToast('图片上传失败：' + res.msg, 'error');
            }
          } catch (e) {
            this.showToast('图片上传失败，请重试', 'error');
          }
        } else {
          this.showToast('图片上传失败，请检查网络', 'error');
        }
      };

      xhr.onerror = () => {
        this.$modal.closeLoading();
        this.showToast('图片上传失败，请检查网络', 'error');
      };

      xhr.send(formData);
    },

    handleVideoUpload(event) {
      const file = event.target.files[0];
      if (!file) return;

      const validTypes = ['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb'];
      if (!validTypes.includes(file.type)) {
        this.showToast('请上传正确的视频格式', 'error');
        return;
      }

      const maxSize = 50 * 1024 * 1024;
      if (file.size > maxSize) {
        this.showToast('视频大小不能超过50MB', 'error');
        return;
      }

      const formData = new FormData();
      formData.append('file', file);
      this.$modal.loading("正在上传视频，请稍候...");

      const xhr = new XMLHttpRequest();
      const uploadUrl = process.env.VUE_APP_BASE_API + '/common/upload';
      xhr.open('POST', uploadUrl);
      xhr.setRequestHeader('Authorization', 'Bearer ' + this.getToken());
      xhr.withCredentials = true;

      xhr.onload = () => {
        this.$modal.closeLoading();
        if (xhr.status === 200) {
          try {
            const res = JSON.parse(xhr.responseText);
            if (res.code === 200) {
              this.localValue = res.url;
              setTimeout(() => {
                this.item.value = this.localValue;
                this.delayedEmitUpdate();
              }, 100);
              this.showToast('视频上传成功！');
            } else {
              this.showToast('视频上传失败：' + res.msg, 'error');
            }
          } catch (e) {
            this.showToast('视频上传失败，请重试', 'error');
          }
        } else {
          this.showToast('视频上传失败，请检查网络', 'error');
        }
      };

      xhr.onerror = () => {
        this.$modal.closeLoading();
        this.showToast('视频上传失败，请检查网络', 'error');
      };

      xhr.send(formData);
    },

    getFullMediaUrl(url) {
      if (!url) return '';
      if (url.startsWith('http')) {
        return url;
      }
      return process.env.VUE_APP_BASE_API + url;
    },

    openVideoPreview() {
      const videoUrl = this.getFullMediaUrl(this.localValue);
      this.$emit('preview-video', videoUrl);
    },

    clearMedia(type) {
      if (window.confirm(`确定要删除这个${type === 'image' ? '图片' : '视频'}吗？`)) {
        this.localValue = '';
        this.item.value = '';
        this.delayedEmitUpdate();
      }
    },

    getToken() {
      return getToken();
    },

    previewFile() {
      this.$emit('preview-file', this.localValue);
    },

    handleTypeChange() {
      if (this.localType === 'object') {
        this.localValue = [];
        this.item.value = [];
      } else {
        this.localValue = '';
        this.item.value = '';
      }
      this.item.type = this.localType;
      this.delayedEmitUpdate();
    },

    delayedEmitUpdate() {
      if (this.updateTimer) {
        clearTimeout(this.updateTimer);
      }
      this.updateTimer = setTimeout(() => {
        this.$emit('update');
      }, 500);
    },

    showToast(message, type = 'success') {
      const toast = document.createElement('div');
      toast.className = `alert alert-${type} fixed top-4 right-4 z-50`;
      toast.innerHTML = `<span>${message}</span>`;
      document.body.appendChild(toast);

      setTimeout(() => {
        toast.remove();
      }, 3000);
    },

    recordCurrentFocus(type) {
      this.currentFocus = type;
    },

    resetFocus() {
      this.currentFocus = null;
    }
  },
  mounted() {
    if (Array.isArray(this.item.value) && this.item.value.length > 0 && this.item.expanded === undefined) {
      this.item.expanded = true;
    }
  },
  beforeDestroy() {
    this.resetFocus();
  }
}
</script>

<style scoped>
/* 容器样式 - 强制完全靠左 */
.item-container {
  border-left: 2px dashed #e5e7eb;
  margin: 0;
  padding: 0;
}

/* 行样式 - 优化布局和间距 */
.item-row {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  padding: 0;
  border-radius: 0;
  transition: background-color 0.2s;
  justify-content: flex-start;
  text-align: left;
  margin: 0;
  transform: translateX(-4px);
}

.item-row:hover {
  background-color: #f9fafb;
}

/* 按钮样式 */
.expand-btn {
  background: none;
  border: none;
  padding: 0.25rem;
  margin-top: 0.5rem;
  cursor: pointer;
  color: #6b7280;
  font-size: 0.75rem;
}

.expand-btn:hover {
  color: #374151;
}

.placeholder-btn {
  width: 1.5rem;
}

/* 层级指示器 */
.level-indicator {
  font-size: 0.75rem;
  font-family: monospace;
  padding: 0.0625rem 0.25rem;
  line-height: 1;
  border-radius: 0.25rem;
  background-color: #f3f4f6;
  color: #6b7280;
  display: inline-flex;
  align-items: center;
  height: auto;
}

/* 输入组样式 */
.input-group {
  flex: 0 0 auto;
  min-width: 0;
  margin: 0;
  padding: 0;
  text-align: left;
  display: block;
  width: auto;
  box-sizing: border-box;
  position: relative;
}

/* 输入框样式 */
.input-field {
  width: 180px;
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
  border: 1px solid #d1d5db;
  border-radius: 0.375rem;
  text-align: left;
  margin: 0;
  box-sizing: border-box;
}

.input-label {
  display: block;
  font-size: 0.875rem;
  font-weight: 300;
  color: #6b7280;
  margin-bottom: 0.25rem;
}

/* 文件上传样式 */
.file-upload {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  width: 100%;
}

.file-input {
  padding: 0.375rem 0.75rem;
  border: 1px solid #d1d5db;
  border-radius: 0.375rem;
  cursor: pointer;
  width: 180px;
  min-width: 180px;
  max-width: 180px;
  box-sizing: border-box;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 媒体预览样式 */
.media-preview {
  position: relative;
  display: inline-block;
  margin-top: 0.5rem;
  margin-left: 2rem;
  border: 1px solid #e5e7eb;
  border-radius: 0.25rem;
  overflow: hidden;
  width: auto;
}

.preview-img {
  max-width: 150px;
  max-height: 100px;
  object-fit: contain;
  display: block;
}

.preview-video {
  max-width: 200px;
  max-height: 120px;
  display: block;
}

/* 媒体预览上的按钮 */
.media-preview .preview-btn,
.media-preview .delete-btn {
  position: absolute;
  top: 0.25rem;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
  opacity: 0.8;
  transition: opacity 0.2s;
}

.media-preview .preview-btn:hover,
.media-preview .delete-btn:hover {
  opacity: 1;
}

.media-preview .preview-btn {
  right: 32px;
  background-color: #007bff;
}

.media-preview .delete-btn {
  right: 4px;
  background-color: #dc3545;
}

/* 对象提示样式 */
.object-hint {
  font-style: italic;
  color: #6b7280;
  font-size: 0.875rem;
  padding: 0.375rem;
  background-color: #f9fafb;
  border: 1px dashed #d1d5db;
  border-radius: 0.375rem;
  margin-left: 2rem;
}

.input-field:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

.input-error {
  border-color: #ef4444;
}

.input-error:focus {
  border-color: #ef4444;
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}

/* 选择框样式 */
.type-select {
  width: 8rem;
}

.select-field {
  width: 100%;
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
  border: 1px solid #d1d5db;
  border-radius: 0.375rem;
  background-color: white;
  cursor: pointer;
}

.select-field:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

/* 操作按钮 */
.action-buttons {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  padding-top: 40px;
}

.add-btn {
  background-color: #10b981;
  border: none;
  color: white;
  width: 32px;
  height: 32px;
  border-radius: 0.375rem;
  cursor: pointer;
  font-size: 0.875rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.2s;
}

.add-btn:hover {
  background-color: #059669;
}

.delete-btn {
  background-color: white;
  border: 1px solid #ef4444;
  color: #ef4444;
  width: 32px;
  height: 32px;
  border-radius: 0.375rem;
  cursor: pointer;
  font-size: 0.875rem;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}

.delete-btn:hover:not(:disabled) {
  background-color: #ef4444;
  color: white;
}

.delete-btn:disabled {
  border-color: #d1d5db;
  color: #9ca3af;
  cursor: not-allowed;
  opacity: 0.5;
}

/* 禁用状态样式 */
.input-field:disabled,
.select-field:disabled,
.file-input:disabled {
  background-color: #f3f4f6;
  color: #9ca3af;
  cursor: not-allowed;
  opacity: 0.7;
}

/* 层级容器样式 */
.item-container {
  position: relative;
  padding-left: 1rem;
  margin-left: 0;
  transition: background-color 0.2s;
  border-left: 1px solid #e5e7eb;
}

.item-container.level-0 {
  padding-left: 0;
  border-left: none;
}

/* 子节点容器 */
.children-container {
  margin-top: 0.25rem;
  border-radius: 0.375rem;
  overflow: hidden;
}

/* 层级连接线 */
.item-row::before {
  content: '';
  position: absolute;
  left: -2rem;
  top: 1.5rem;
  width: 2rem;
  height: 1px;
  background-color: #cbd5e1;
}

.children-container::before {
  content: '';
  position: absolute;
  left: -1rem;
  top: 1.5rem;
  width: 1px;
  height: calc(100% - 1.5rem);
  background-color: #cbd5e1;
}

.level-0 .item-row::before,
.level-0 .children-container::before {
  display: none;
}

/* 优化层级指示器样式 */
.level-indicator {
  font-size: 0.75rem;
  font-family: monospace;
  padding: 0.125rem 0.375rem;
  border-radius: 0.25rem;
  background-color: #e5e7eb;
  color: #6b7280;
  margin-top: 0.5rem;
  min-width: 1.25rem;
  text-align: center;
}

/* 错误提示 */
.error-text {
  color: #ef4444;
  font-size: 0.75rem;
  margin-top: 0.25rem;
}

/* 最小宽度 */
.min-w-0 {
  min-width: 0;
}
</style>
